package application.manager;

import application.anno.Group;
import application.anno.Layout;
import application.constant.Constant;
import application.exception.NotFoundNecessaryAnnotationException;
import application.messager.Messager;
import application.parasitic.ParasiticLayout;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;

import java.io.IOException;
import java.net.URL;
import java.util.*;

public class ParasiticManagerStack {

    private static ParasiticManagerStack parasiticManagerStack = new ParasiticManagerStack();

    private volatile Map<String, ParasiticGroup> parasiticGroups;

    private ParasiticManagerStack() {
        parasiticGroups = new HashMap<>();
    }

    public static class ParasiticGroup {
        private volatile LinkedHashMap<Class<? extends ParasiticLayout>, ParasiticLayout> parasiticLayouts;

        private volatile Stack<ParasiticLayout> backup;

        private volatile Stack<ParasiticLayout> forward;

        private volatile static ParasiticGroup parasiticGroup = new ParasiticGroup();

        public ParasiticGroup() {
            parasiticLayouts = new LinkedHashMap<>();
            backup = new Stack<>();
            forward = new Stack<>();
        }

        public synchronized void register(Class<? extends ParasiticLayout> cls, ParasiticLayout parasiticLayout) {
            this.parasiticLayouts.put(cls, parasiticLayout);
        }

        public synchronized void release(ParasiticLayout parasiticLayout) {
            if (parasiticLayouts == null || parasiticLayouts.isEmpty()) {
                return;
            }
            parasiticLayouts.remove(parasiticLayout);
        }

        public synchronized void pushBack(ParasiticLayout parasiticLayout) {
            this.backup.push(parasiticLayout);
        }

        public ParasiticLayout popBack() {
            return this.backup.pop();
        }

        public synchronized void pushForward(ParasiticLayout parasiticLayout) {
            this.forward.push(parasiticLayout);
        }

        public synchronized ParasiticLayout popForward() {
            return this.forward.pop();
        }
    }

    public static ParasiticManagerStack getInstance() {
        if (parasiticManagerStack == null) {
            parasiticManagerStack = new ParasiticManagerStack();
        }
        return parasiticManagerStack;
    }

    /**
     * 注册寄生布局
     *
     * @param cls 寄生布局处理器类对象
     * @return 寄生布局对象
     * @throws IOException 当找不到必要信息时，会抛出此异常
     */
    public synchronized ParasiticLayout register(Class<? extends ParasiticLayout> cls) throws IOException {
        Layout layout = cls.getAnnotation(Layout.class);
        if (layout == null) {
            throw new NotFoundNecessaryAnnotationException("Not found Layout annotation, can not get layout resource");
        }
        Group group = cls.getAnnotation(Group.class);
        if (group == null) {
            throw new NotFoundNecessaryAnnotationException("Not found Group annotation, can not get group information");
        }
        ParasiticGroup parasiticGroup = this.parasiticGroups.get(group.value());
        if (parasiticGroup == null) {
            parasiticGroup = new ParasiticGroup();
        }
        this.parasiticGroups.put(group.value(), parasiticGroup);
        String layoutPath = layout.value();
        URL resource = getClass().getClassLoader().getResource("layout/".concat(layoutPath));
        FXMLLoader fxmlLoader = new FXMLLoader(resource);
        Pane pane = fxmlLoader.load();
        ParasiticLayout parasiticLayout;
        parasiticLayout = fxmlLoader.getController();
        parasiticGroup.register(cls, parasiticLayout);
        parasiticLayout.setPane(pane);
        return parasiticLayout;
    }

    /**
     * 调用此方法将寄生布局压入回退栈中
     *
     * @param group           布局所在的组
     * @param parasiticLayout 被压入回退栈的寄生布局
     */
    public synchronized void pushBack(String group, ParasiticLayout parasiticLayout) {
        // 提供回退栈
        ParasiticGroup parasiticGroup = this.parasiticGroups.get(group);
        if (parasiticGroup == null) {
            parasiticGroup = new ParasiticGroup();
        }
        parasiticGroup.pushBack(parasiticLayout);
        parasiticLayout.setVisible(false);
    }

    public synchronized ParasiticLayout back(String group) {
        ParasiticGroup parasiticGroup = this.parasiticGroups.get(group);
        if (parasiticGroup == null) {
            // 发送广播，提示没有可使用的合法组。
            Messager messager = new Messager(Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_ACTION);
            messager.put(Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_FLAG, Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_MESSAGE);
            messager.sendMessage();
            return null;
        }
        if (parasiticGroup.backup.isEmpty()) {
            // 发送广播，没有可弹出的寄生布局
            Messager messager = new Messager(Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_ACTION);
            messager.put(Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_FLAG, Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_MESSAGE);
            messager.sendMessage();
            return null;
        }
        ParasiticLayout pop = parasiticGroup.popBack();
        pop.setVisible(true);
        return pop;
    }

    public synchronized void pushForward(String group, ParasiticLayout parasiticLayout) {
        ParasiticGroup parasiticGroup = this.parasiticGroups.get(group);
        if (parasiticGroup == null) {
            parasiticGroup = new ParasiticGroup();
        }
        parasiticGroup.forward.push(parasiticLayout);
        parasiticLayout.setVisible(false);
    }

    public synchronized void forward(String group) {
        ParasiticGroup parasiticGroup = this.parasiticGroups.get(group);
        if (parasiticGroup == null) {
            // 发送广播，提示没有可使用的合法组。
            Messager messager = new Messager(Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_ACTION);
            messager.put(Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_FLAG, Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_MESSAGE);
            messager.sendMessage();
            return;
        }
        if (parasiticGroup.forward.isEmpty()) {
            // 发送广播，没有可弹出的寄生布局
            Messager messager = new Messager(Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_ACTION);
            messager.put(Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_FLAG, Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_MESSAGE);
            messager.sendMessage();
            return;
        }
        ParasiticLayout pop = parasiticGroup.popForward();
        pop.setVisible(true);
    }

    public synchronized void release(String group, ParasiticLayout parasiticLayout) {
        ParasiticGroup parasiticGroup = this.parasiticGroups.get(group);
        if (parasiticGroup == null) {
            // 发送广播，提示没有可使用的合法组。
            Messager messager = new Messager(Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_ACTION);
            messager.put(Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_FLAG, Constant.ParasiticLayoutMessage.NO_LEGAL_GROUP_MESSAGE);
            messager.sendMessage();
            return;
        }
        if (parasiticGroup.backup.isEmpty()) {
            // 发送广播，没有可弹出的寄生布局
            Messager messager = new Messager(Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_ACTION);
            messager.put(Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_FLAG, Constant.ParasiticLayoutMessage.NO_WAITING_PARASITIC_LAYOUT_MESSAGE);
            messager.sendMessage();
            return;
        }
        parasiticGroup.forward.remove(parasiticLayout);
        parasiticGroup.backup.remove(parasiticLayout);
    }
}
